import useToast from '@/hooks/useToast';
import {
  type ChangeEvent,
  type FormEvent,
  useContext,
  useEffect,
  useState,
} from 'react';
import type {
  IDifference,
  ISectionDetails,
  IUpdateSectionBody,
  IUploadSectionCover,
  IUploadSectionCoverBody,
} from '@/interfaces';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import type { TBody } from '@/types';
import { updateSection, uploadSectionCover } from '@/services/api';
import diff from 'microdiff';
import { getDiffData, getFilterData, isEmpty, isHttpOrHttps } from '@/lib/tool';
import { SectionAdminContext } from '@/contexts/admin/forum/section';
import Nodata from '@/app/[locale]/common/nodata/nodata';

export default function UpdateSectionInfo({
  details,
}: {
  details: ISectionDetails;
}) {
  const { show } = useToast();
  const [form, setForm] = useState<{
    name: string;
    sort: number;
    cover: string;
    overview: string;
    uploadCover: string;
    uploadCoverFile: Blob | null;
    uploadCoverObjectUrl: string;
  }>({
    name: '',
    sort: 0,
    cover: '',
    overview: '',
    uploadCover: '',
    uploadCoverFile: null,
    uploadCoverObjectUrl: '',
  });
  const [differenceData, setDifferenceData] = useState<IDifference[]>([]);
  const context = useContext(SectionAdminContext);
  const metadata = context.metadata;
  const [isPreviewCover, setIsPreviewCover] = useState(false);
  const queryClient = useQueryClient();

  const updateSectionMutation = useMutation(
    async (variables: TBody<IUpdateSectionBody>) => {
      await updateSection(variables);
      await queryClient.invalidateQueries([
        '/forum',
        '/sections',
        details.basic.id,
        '/details',
      ]);
    },
  );

  const uploadSectionCoverMutation = useMutation(
    async (variables: TBody<IUploadSectionCoverBody>) => {
      return (await uploadSectionCover(variables)) as IUploadSectionCover;
    },
  );

  useEffect(() => {
    if (details) {
      const { basic } = details;
      setForm({
        name: basic.name,
        sort: basic.sort,
        cover: basic.cover || '',
        overview: basic.overview || '',
        uploadCover: '',
        uploadCoverFile: null,
        uploadCoverObjectUrl: '',
      });
    }
  }, [details]);
  useEffect(() => {
    if (details) {
      const { basic } = details;
      const differences = diff(
        {
          name: basic.name,
          sort: basic.sort,
          cover: basic.cover || '',
          overview: basic.overview || '',
        },
        {
          name: form.name,
          sort: form.sort,
          cover: form.cover,
          overview: form.overview,
        },
      );
      setDifferenceData(differences);
    }
  }, [form, details]);

  function onChangeForm(
    e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
  ) {
    const name = e.target.name;
    const value = e.target.value;

    if (name === 'uploadCover') {
      if (form.uploadCoverObjectUrl) {
        URL.revokeObjectURL(form.uploadCoverObjectUrl);
      }

      const files = (e.target as HTMLInputElement).files;
      if (!files) {
        show({
          type: 'DANGER',
          message: '文件不存在',
        });
        return;
      }

      const file = files[0];
      setForm({
        ...form,
        uploadCover: value,
        uploadCoverFile: file,
        uploadCoverObjectUrl: URL.createObjectURL(file),
      });
    } else if (name === 'sort') {
      setForm({ ...form, sort: parseInt(value) });
    } else {
      setForm({ ...form, [name]: value });
    }
  }

  async function onClickSave(e: FormEvent<HTMLFormElement>) {
    try {
      e.preventDefault();
      e.stopPropagation();

      const body = getFilterData(getDiffData(differenceData));
      handleDefaultData(body);

      if (isEmpty(body)) {
        show({
          type: 'SUCCESS',
          message: '保存完成',
        });
        return;
      }

      await updateSectionMutation.mutateAsync({
        id: details.basic.id,
        data: body,
      });

      clearData();
      show({
        type: 'SUCCESS',
        message: '保存完成',
      });
    } catch (e) {
      updateSectionMutation.reset();
      show({
        type: 'DANGER',
        message: e,
      });
    }
  }

  function handleDefaultData(data: Record<string, any>) {
    const overview = form.overview || '';
    if (overview === '') {
      data.overview = '';
    }
  }

  function clearData() {
    setDifferenceData([]);
  }

  async function onClickUploadCover() {
    try {
      const uploadCoverFile = form.uploadCoverFile;
      if (!uploadCoverFile) {
        show({
          type: 'DANGER',
          message: '请选择封面文件后再上传',
        });
        return;
      }

      const { urls } = await uploadSectionCoverMutation.mutateAsync({
        id: details.basic.id,
        data: {
          file: uploadCoverFile,
        },
      });

      if (form.uploadCoverObjectUrl) {
        URL.revokeObjectURL(form.uploadCoverObjectUrl);
      }

      setForm({
        ...form,
        cover: metadata!.env.APP_OSS_SERVER + urls.default,
        uploadCover: '',
        uploadCoverFile: null,
        uploadCoverObjectUrl: '',
      });

      show({
        type: 'SUCCESS',
        message: '上传完成',
      });
    } catch (e) {
      show({
        type: 'DANGER',
        message: e,
      });
    }
  }

  function onClickCloseCoverFile() {
    if (form.uploadCoverObjectUrl) {
      URL.revokeObjectURL(form.uploadCoverObjectUrl);
    }

    setForm({
      ...form,
      uploadCover: '',
      uploadCoverFile: null,
      uploadCoverObjectUrl: '',
    });
    setIsPreviewCover(false);
  }

  function onClickPreviewCover() {
    setIsPreviewCover(!isPreviewCover);
  }

  return (
    <div className="row">
      <div className="col">
        <form onSubmit={onClickSave} className="vstack gap-4">
          <div>
            <label className="form-label">名称</label>
            <input
              type="text"
              className="form-control"
              name="name"
              value={form.name}
              onChange={onChangeForm}
              aria-describedby="name"
              placeholder="请输入版块名称，建议简明扼要"
            />
          </div>

          <div>
            <div>
              <label className="form-label">封面</label>
              <textarea
                className="form-control"
                name="cover"
                value={form.cover}
                onChange={onChangeForm}
                rows={1}
                placeholder="请输入封面链接或者上传图片"
              ></textarea>
            </div>

            <div className="my-2 d-flex align-items-center">
              <div className="input-group align-items-center">
                <input
                  type="file"
                  accept="image/*"
                  className="form-control"
                  name="uploadCover"
                  value={form.uploadCover}
                  onChange={onChangeForm}
                  aria-describedby="上传封面"
                  aria-label="Upload"
                />
                <button
                  disabled={uploadSectionCoverMutation.isLoading}
                  onClick={onClickUploadCover}
                  className="btn btn-outline-secondary"
                  type="button"
                >
                  {uploadSectionCoverMutation.isLoading && (
                    <span
                      className="spinner-border spinner-border-sm me-2"
                      role="status"
                      aria-hidden="true"
                    ></span>
                  )}
                  上传
                </button>
                <button
                  type="button"
                  onClick={onClickPreviewCover}
                  className="btn btn-outline-secondary"
                >
                  {isPreviewCover ? '取消预览' : '预览'}
                </button>
                {form.uploadCoverObjectUrl && (
                  <button
                    type="button"
                    onClick={onClickCloseCoverFile}
                    className="btn-close ms-3"
                    aria-label="Close"
                  ></button>
                )}
              </div>
            </div>

            {isPreviewCover && metadata && (
              <>
                {form.uploadCoverObjectUrl || form.cover ? (
                  <div className="hstack gap-4">
                    <div
                      style={{ maxWidth: 142, maxHeight: 80 }}
                      className="ratio ratio-16x9"
                    >
                      <img
                        src={
                          form.uploadCoverObjectUrl
                            ? form.uploadCoverObjectUrl
                            : isHttpOrHttps(form.cover)
                            ? form.cover
                            : metadata.env.APP_OSS_SERVER + form.cover
                        }
                        alt="封面预览"
                        title="建议封面比例为 16/9"
                        className="object-fit-contain"
                      />
                    </div>
                    <div
                      style={{ maxWidth: 260, maxHeight: 146 }}
                      className="ratio ratio-16x9"
                    >
                      <img
                        src={
                          form.uploadCoverObjectUrl
                            ? form.uploadCoverObjectUrl
                            : isHttpOrHttps(form.cover)
                            ? form.cover
                            : metadata.env.APP_OSS_SERVER + form.cover
                        }
                        alt="封面预览"
                        title="建议封面比例为 16/9"
                        className="object-fit-contain"
                      />
                    </div>
                    <div
                      style={{
                        maxWidth: 378,
                        maxHeight: 213,
                      }}
                      className="ratio ratio-16x9"
                    >
                      <img
                        src={
                          form.uploadCoverObjectUrl
                            ? form.uploadCoverObjectUrl
                            : isHttpOrHttps(form.cover)
                            ? form.cover
                            : metadata.env.APP_OSS_SERVER + form.cover
                        }
                        alt="封面预览"
                        title="建议封面比例为 16/9"
                        className="object-fit-contain"
                      />
                    </div>
                  </div>
                ) : (
                  <Nodata />
                )}
              </>
            )}
          </div>

          <div>
            <label className="form-label">
              <span>概述</span>
              {form.overview && (
                <span className="text-muted user-select-none">
                  (当前长度：{form.overview.length})
                </span>
              )}
            </label>
            <textarea
              className="form-control"
              name="overview"
              value={form.overview}
              onChange={onChangeForm}
              aria-describedby="overview"
              rows={2}
              placeholder="请输入版块概述，建议字数在 150 个字以内"
            />
          </div>

          <div>
            <label className="form-label">排序</label>
            <input
              type="number"
              min={0}
              className="form-control"
              name="sort"
              value={form.sort}
              onChange={onChangeForm}
              aria-describedby="sort"
              placeholder="请输入版块排序值，最小为 0"
            />
          </div>

          <button
            type="submit"
            disabled={updateSectionMutation.isLoading}
            className="btn btn-success w-25 my-4"
          >
            {updateSectionMutation.isLoading && (
              <span
                className="spinner-border spinner-border-sm me-2"
                role="status"
                aria-hidden="true"
              ></span>
            )}
            更新
          </button>
        </form>
      </div>
    </div>
  );
}
